#include <stdlib.h>
#include <stdio.h>
#include "table.h"

#define FIN_BLOCK -2
#define FIN_FONCTION -3

int compteur = 0;

struct table {
  struct var* loc;
  struct var* inst;
  struct var* glo;
  struct var* comp;
};



struct table * initTable(){
  struct table * tab = malloc(sizeof(struct var));
  tab->loc = NULL;
  tab->inst = NULL;
  tab->glo = NULL;
  tab->comp = NULL;
  return tab;
}

void freeTable(struct var* p)
{
  struct var* tmp;
  while(p !=NULL)
    {
      if(p->nom != NULL)
	free(p->nom);
      if(p->reg != NULL)
	free(p->reg);
      if(p->code != NULL)
	free(p->code);
      tmp = p;
      p = p->prec;
      free(tmp);
    }
}

void supprTable(struct table* tab)
{
  freeTable(tab->loc);
  freeTable(tab->inst);
  freeTable(tab->glo);
  freeTable(tab->comp); 
  free(tab);
}


struct var * creerVar(struct table * tab, char * nom, int type)
{
  struct var * var = malloc(sizeof(struct var));
  var->nom = nom;
  var->type = type;
  var->code = NULL;
  var->allocated = 0;
  if(nom == NULL)
    {
      var->reg = malloc(sizeof(char)*((compteur/10)+4));
      var->reg[0] = '%';
      var->reg[1] = 'r';
      sprintf(&(var->reg[2]),"%d",compteur);
      var->portee = COMP;
      var->prec = tab->comp;
      tab->comp = var;
      compteur++;
    }
  else if(var->nom[0] == '$')
    {
      var->reg = malloc(sizeof(char)*(strlen(nom)+3));
      var->reg[0] = '@';
      var->reg[1] = 'u';
      strcpy(&(var->reg[2]),nom);
      var->portee = GLOBAL;
      var->prec = tab->glo;
      tab->glo = var;
    }
  else if (var->nom[0] == '@')
    {
      var->reg = malloc(sizeof(char)*(strlen(nom)+3));
      var->reg[0] = '@';
      var->reg[1] = 'u';
      var->portee = INSTANCE;
      var->prec = tab->inst;
      tab->inst = var;
    }
  else
    {
      var->reg = malloc(sizeof(char)*(strlen(nom)+3));
      var->reg[0] = '%';
      var->reg[1] = 'u';
      strcpy(&(var->reg[2]),nom);
      var->portee = LOCAL;
      var->prec = tab->loc;
      tab->loc = var;
    }

  return var;
}


int estType(struct var * var , int type){
  return var->type == type;
}

int memeType(struct var * var1, struct var * var2){
  return var1->type==var2->type;
}

struct var* existeLocale(struct table * tab, char * nom){
  struct var * pointeur;
  for(pointeur=tab->loc;pointeur != NULL && pointeur->type!=FIN_FONCTION;pointeur=pointeur->prec){
    if(pointeur->type!=FIN_BLOCK && strcmp(pointeur->nom,nom)==0)  
      return pointeur;
  }
  return NULL;
}

struct var* existeGlobale(struct table * tab, char * nom){
  struct var * pointeur;
  for(pointeur=tab->glo;pointeur!=NULL;pointeur=pointeur->prec){
    if(strcmp(pointeur->nom,nom)==0){
      return pointeur;
    }
  }
  return NULL;
}

struct var* existe(struct table * tab, char * nom){
  if(nom[0] == '$')
    return existeGlobale(tab,nom);
  else 
    return existeLocale(tab,nom);
}

void ajouterCode(struct var* var, char* code)
{
  if(code !=NULL)
    {
      if(var->code == NULL)
	{
	  var->code = strdup(code);
	}
      else
	{
	  char * tmp = var->code;
	  var->code = malloc(sizeof(char)*(strlen(code)+strlen(tmp)+1));
	  sprintf(var->code,"%s%s", tmp, code);
	  free(tmp);
	}
    }
}

void effacerCode(struct var* var)
{
    if(var->code != NULL)
      {
	free(var->code);
	var->code = NULL;
      }
}


void DebugAfficher(struct var * var){
  printf("nom: %s \n"
	 "reg: %s \n"
	 "type: %d \n"
	 "portee: %d \n"
	 "code: %s \n\n"
	 ,var->nom
	 ,var->reg
	 ,var->type
	 ,var->portee
	 ,var->code);
}
